<?php

declare(strict_types=1);

namespace app\worker;

use GatewayWorker\Lib\Gateway;
use think\facade\Log;
use app\service\user\AuthService;

class Events
{
    /**
     * 当客户端连接时触发
     * @param int $clientId 连接的客户端ID
     */
    public static function onConnect($clientId)
    {
        Log::debug("客户端连接:cliendId [{clientId}] ", ['clientId' => $clientId]);
    }

    /**
     * 当客户端发来消息时触发
     * @param int $clientId 发消息的客户端ID
     * @param mixed $message 消息内容
     */
    public static function onMessage($clientId, $message)
    {
        // 记录原始消息信息，做适当的序列化处理
        $logMessage = self::formatMessageForLog($message);
        Log::debug("收到客户端[{clientId}]消息:[{message}],消息类型:[{type}] ", [
            'clientId' => $clientId,
            'message' => $logMessage,
            'type' => gettype($message)
        ]);

        // 解析消息
        $data = self::parseMessage($message);

        if (!$data) {
            return;
        }
        switch ($data['type']) {
            case 'bind':
                // 处理用户绑定请求
                self::handleBind($clientId, $data);
                break;

            case 'ping':
                Log::debug("收到客户端[{clientId}]心跳请求:[{message}]", [
                    'clientId' => $clientId,
                    'message' => $logMessage
                ]);
                // 心跳响应
                Gateway::sendToClient($clientId, json_encode(['type' => 'pong']));
                break;
            default:
                Log::warning("未知消息类型:{} " . $data['type']);
        }
    }

    /**
     * 处理用户绑定请求（通过token解析user_id）
     * @param int $clientId 客户端ID
     * @param array $data 消息数据
     */
    protected static function handleBind($clientId, $data)
    {
        $rawToken = $data['accesstoken'] ?? ($data['token'] ?? null);
        if (!is_string($rawToken)) {
            Log::warning("绑定请求缺少token参数!");
            Gateway::sendToClient($clientId, json_encode([
                'type' => 'bind_error',
                'message' => '绑定请求缺少token参数'
            ]));
            return;
        }

        $token = trim($rawToken);
        if (stripos($token, 'bearer ') === 0) {
            $token = trim(substr($token, 7));
        }

        try {
            // 解析token获取user_id
            $authService = app(AuthService::class);
            $payload = $authService->websocketLogin($token);
            $userId = $payload['user_id'] ?? null;
            $groups = $payload['groups'] ?? [];
            if (!is_array($groups)) {
                $groups = [];
            }
            if (empty($groups) && is_string($payload['group'] ?? null)) {
                $groups[] = (string) $payload['group'];
            }
            if (empty($groups)) {
                Log::warning("用户组数据格式错误: " . json_encode($payload));
                Gateway::sendToClient($clientId, json_encode([
                    'type' => 'bind_error',
                    'message' => '用户组数据格式错误'
                ]));
                return;
            }

            $groupNames = array_values(array_filter(array_map(static fn($value) => is_string($value) ? trim($value) : '', $groups)));
            if ($userId !== null) {
                $groupNames[] = 'user_' . (int) $userId;
            }
            $groupNames = array_values(array_unique(array_filter($groupNames, static fn($value) => $value !== '')));

            foreach ($groupNames as $groupName) {
                Gateway::joinGroup($clientId, $groupName);
            }
            Gateway::setSession($clientId, [
                'user_id' => $userId,
                'groups' => $groupNames,
                'connected_at' => date('c'),
            ]);

            Log::debug("绑定成功: groups:[{groups}]", [
                'groups' => implode(',', $groupNames),
            ]);
            // 发送绑定成功消息
            Gateway::sendToClient($clientId, json_encode([
                'type' => 'bind_success',
                'message' => '绑定成功',
                'groups' => $groupNames
            ]));
        } catch (\Exception $e) {
            Log::error("用户绑定失败:[{message}]", [
                'message' => $e->getMessage(),
            ]);
            // 或类似的写法
            Gateway::sendToClient($clientId, json_encode([
                'type' => 'bind_error',
                'message' => '用户绑定失败: ' . $e->getMessage()
            ]));
        }
    }

    /**
     * 当客户端断开连接时触发
     * @param int $clientId 断开连接的客户端ID
     */
    public static function onClose($clientId)
    {
        Log::debug("客户端[{clientId}]断开连接: ", ['clientId' => $clientId]);
        // GatewayWorker会自动处理UID解绑
    }
    protected static function parseMessage($message): ?array
    {

        // 解析消息为数组格式
        if (is_array($message)) {
            // 如果消息已经是数组，直接使用
            $data = $message;
        } elseif (is_string($message)) {
            // 如果消息是字符串，尝试解析为数组
            $data = json_decode($message, true);
        } else {
            Log::warning("消息格式错误，不支持的类型: " . gettype($message));
            return null;
        }

        // 验证解析结果
        if (!is_array($data)) {
            Log::warning("消息解析失败，结果不是数组", [
                'message' => is_string($message) ? $message : json_encode($message)
            ]);
            return null;
        }

        if (!isset($data['type'])) {
            Log::warning("消息缺少type字段", [
                'message' => is_string($message) ? $message : json_encode($message)
            ]);
            return null;
        }

        return $data;
    }
    /**
     * 格式化消息用于日志记录
     * @param mixed $message 消息内容
     * @return string 格式化后的字符串
     */
    protected static function formatMessageForLog($message): string
    {
        if (is_string($message)) {
            return $message;
        } elseif (is_array($message) || is_object($message)) {
            $encoded = json_encode($message, JSON_UNESCAPED_UNICODE);
            return $encoded !== false ? $encoded : serialize($message);
        } elseif (is_resource($message)) {
            return 'Resource(type=' . get_resource_type($message) . ')';
        } else {
            return (string)$message;
        }
    }
}
